package net.cyue.easyconfiguration.node.definition;

import net.cyue.easyconfiguration.node.NodeType;
import net.cyue.easyconfiguration.node.api.INodeTypeConverter;
import net.cyue.easyconfiguration.node.converter.Node2StringConverter;

public class ArrayNodeDefinition extends AbstractNodeDefinition {

    private AbstractNodeDefinition elementDefinition;
    private Class<?> elementJavaType;

    public ArrayNodeDefinition(
        AbstractNodeDefinition parent,
        String name,
        String... paths
    ) {
        super(parent, NodeType.ARRAY, name, paths);
        this.setElementDefinition(
            new AnyNodeDefinition(this, NodeType.ANY, new Node2StringConverter<>(), "element")
        );
    }
    public ArrayNodeDefinition(
        AbstractNodeDefinition parent,
        INodeTypeConverter typeConverter,
        String name,
        String... paths
    ) {
        super(parent, NodeType.ARRAY, typeConverter, name, paths);
        this.setElementDefinition(
            new AnyNodeDefinition(this, NodeType.ANY, new Node2StringConverter<>(), "element")
        );
    }
    public ArrayNodeDefinition(
        AbstractNodeDefinition parent,
        NodeType elementNodeType,
        String name,
        String... paths
    ) {
        super(parent, NodeType.ARRAY, name, paths);
        this.setElementDefinition(
            new AnyNodeDefinition(this, elementNodeType, "element")
        );
    }
    public ArrayNodeDefinition(
        AbstractNodeDefinition parent,
        INodeTypeConverter typeConverter,
        NodeType elementNodeType,
        String name,
        String... paths
    ) {
        super(parent, NodeType.ARRAY, typeConverter, name, paths);
        this.setElementDefinition(
            new AnyNodeDefinition(this, elementNodeType, "element")
        );
    }
    public ArrayNodeDefinition(
        AbstractNodeDefinition parent,
        INodeTypeConverter typeConverter,
        NodeType elementNodeType,
        INodeTypeConverter elementTypeConverter,
        String name,
        String... paths
    ) {
        super(parent, NodeType.ARRAY, typeConverter, name, paths);
        this.setElementDefinition(
            new AnyNodeDefinition(this, elementNodeType, elementTypeConverter, "element")
        );
    }

    public void setElementDefinition(AbstractNodeDefinition elementDefinition) {
        this.elementDefinition = elementDefinition;
    }
    public void setElementNodeType(NodeType elementNodeType) {
        INodeTypeConverter tempElementTypeConverter = this.elementDefinition.getTypeConverter();
        if (elementNodeType == NodeType.ARRAY) {
            ArrayNodeDefinition elementDefinition = new ArrayNodeDefinition(this, "element", "*");
            elementDefinition.setTypeConverter(tempElementTypeConverter);
            this.setElementDefinition(elementDefinition);
        } else if (elementNodeType == NodeType.TABLE) {
            TableNodeDefinition elementDefinition = new TableNodeDefinition(this, "element", "*");
            elementDefinition.setTypeConverter(tempElementTypeConverter);
            this.setElementDefinition(elementDefinition);
        } else {
            this.elementDefinition.setNodeType(elementNodeType);
        }
    }
    public void setElementJavaType(Class<?> elementJavaType) {
        this.elementJavaType = elementJavaType;
        this.elementDefinition.setJavaType(elementJavaType);
    }

    public void setElementTypeConverter(INodeTypeConverter typeConverter) {
        this.elementDefinition.setTypeConverter(typeConverter);
    }

    public AbstractNodeDefinition getElementDefinition() {
        return this.elementDefinition;
    }
    public NodeType getElementNodeType() {
        return this.elementDefinition.getType();
    }
    public Class<?> getElementJavaType() {
        Class<?> componentType = this.elementJavaType;
        if (componentType == null) {
            componentType = this.elementDefinition.getJavaType();
        }
        return componentType;
    }
}
